/* 
 * File:   CmsgLink.cpp
 * Author: root
 * 
 * Created on May 20, 2019, 8:48 AM
 */
#include <cstdlib>
#include <string.h>
#include <stdio.h>
#include "CmsgLink.h"

CmsgLink::CmsgLink() 
{
    nodeNum = 0;
    
    pNode = NULL;
    
    pthread_mutex_init(&mMutex, NULL);
}

CmsgLink::CmsgLink(const CmsgLink& orig) 
{
    
}

CmsgLink::~CmsgLink() 
{
    pthread_mutex_destroy(&mMutex);
}

/**********************************************************************
* 函数名称：CmsgLink::createNode
* 功能描述：创建链表头结点
* 输入参数：
* 输出参数：
* 返 回 值：return 0:suceed -1:failed
* 其它说明：
***********************************************************************/
int CmsgLink::createNode(void)
{
    if(pNode == NULL){
        pNode = (list_node *)malloc(sizeof(list_node));
    }
    if(pNode == NULL){
        return -1;
    }
    else{
        memset((void *)pNode, 0, sizeof(list_node));
        pNode->pNext = NULL;
        return 0;
    }
}

/**********************************************************************
* 函数名称：CmsgLink::getNodeNum
* 功能描述：获取有数据节点的个数
* 输入参数：
* 输出参数：
* 返 回 值：return 0:suceed -1:failed
* 其它说明：
***********************************************************************/
int CmsgLink::getNodeNum(void)
{
    int num = 0;
    pthread_mutex_lock(&mMutex);
    num = nodeNum;
    pthread_mutex_unlock(&mMutex);
    return num;
}

/**********************************************************************
* 函数名称：CmsgLink::addNode
* 功能描述：创建链表子结点
* 输入参数：
* 输出参数：
* 返 回 值：return 0:suceed -1:failed
* 其它说明：
***********************************************************************/
int CmsgLink::addNode(int id, int timeout, void *pData, int pDatalen)
{
    list_node *node;

    if(pNode == NULL){
        createNode();
    }
    if(pNode == NULL) {
        printf("create root Node failed\r\n");
        return -1;
    }
    
    pthread_mutex_lock(&mMutex);
    
    node = pNode;
    while(node->pNext != NULL){
        node = node->pNext;
    }
    node->pNext = (list_node *)malloc(sizeof(list_node));
    if(node->pNext == NULL){
        printf("create child Node failed\r\n");
        pthread_mutex_unlock(&mMutex);
        return -1;
    }
    
    node = node->pNext;
    node->element.id = id;
    node->element.timeout = timeout;
    node->element.pDataLen = pDatalen;
    node->element.pData = malloc(pDatalen);
    node->element.arg = NULL;
    node->element.callback = NULL;
    if(node->element.pData != NULL){
        memcpy(node->element.pData, pData, pDatalen);
    }
    else{
        printf("addNode has not enough empty for pData\r\n");
        node = NULL;
        free(node);
        pthread_mutex_unlock(&mMutex);
        return -1;
    }
    node->pNext = NULL;
    
    nodeNum++;
    pthread_mutex_unlock(&mMutex);
    return 0;
}

int CmsgLink::addNode(int id, int timeout, void *pData, int pDatalen, void *arg, Callback callback)
{
    list_node *node;

    if(pNode == NULL){
        createNode();
    }
    if(pNode == NULL) {
        printf("create root Node failed\r\n");
        return -1;
    }
    
    pthread_mutex_lock(&mMutex);
    
    node = pNode;
    while(node->pNext != NULL){
        node = node->pNext;
    }
    node->pNext = (list_node *)malloc(sizeof(list_node));
    if(node->pNext == NULL){
        printf("create child Node failed\r\n");
        pthread_mutex_unlock(&mMutex);
        return -1;
    }
    
    node = node->pNext;
    node->element.id = id;
    node->element.timeout = timeout;
    node->element.pDataLen = pDatalen;
    node->element.pData = malloc(pDatalen);
    node->element.arg = arg;
    node->element.callback = callback;
    if(node->element.pData != NULL){
        memcpy(node->element.pData, pData, pDatalen);
    }
    else{
        printf("addNode has not enough empty for pData\r\n");
        node = NULL;
        free(node);
        pthread_mutex_unlock(&mMutex);
        return -1;
    }
    node->pNext = NULL;
    
    nodeNum++;
    pthread_mutex_unlock(&mMutex);
    return 0;
}

/**********************************************************************
* 函数名称：CmsgLink::deleteNode
* 功能描述：删除链表子结点
* 输入参数：
* 输出参数：
* 返 回 值：return 0:suceed -1:failed, -2:id doesn't exit
* 其它说明：
***********************************************************************/
int CmsgLink::deleteNode(int id)
{
    list_node *node, *preNode;
    if((pNode == NULL)) return -1;

    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        if(node->element.id == id){
            preNode->pNext = node->pNext;
            free(node->element.pData);
            free(node);
            node = NULL;
            nodeNum--;
            pthread_mutex_unlock(&mMutex);
            return 0;
        }
        preNode = node;
    }

    pthread_mutex_unlock(&mMutex);
    return -2;
}

/**********************************************************************
* 函数名称：CmsgLink::isNodeIdExist
* 功能描述：通过id判断node是否存在
* 输入参数：
* 输出参数：
* 返 回 值：true 存在
* 其它说明：
***********************************************************************/
bool CmsgLink::isNodeIdExist(int id)
{
    list_node *node, *preNode;
    if((pNode == NULL)) return false;

    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        if(node->element.id == id){
            pthread_mutex_unlock(&mMutex);
            return true;
        }
        preNode = node;
    }

    pthread_mutex_unlock(&mMutex);
    return false;
}

/**********************************************************************
* 函数名称：CmsgLink::tickNode
* 功能描述：计算一次超时时间
* 输入参数：已经过的时间ms
* 输出参数：
* 返 回 值：返回已超时的个数
* 其它说明：
***********************************************************************/
int CmsgLink::tickNode(int passTime)
{
    int timeoutCount = 0;
    list_node *node, *preNode;
    if((pNode == NULL)) return -1;
    
    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        node->element.timeout -= passTime;
        if(node->element.timeout <= 0){
            timeoutCount++;
        }
        preNode = node;
    }

    pthread_mutex_unlock(&mMutex);
    
    return timeoutCount;
}

/**********************************************************************
* 函数名称：CmsgLink::getTimeoutNodeData
* 功能描述：获取一个超时节点的数据
* 输入参数：pData:数据的保存地址，maxLen:pData最大长度
* 输出参数：
* 返 回 值：返回数据的长度
* 其它说明：
***********************************************************************/
int CmsgLink::getTimeoutNodeData(void *pData, int &maxLen)
{
    int len = -1;
    list_node *node, *preNode;
    if((pNode == NULL) || (pData == NULL)) return -1;
    
    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        if(node->element.timeout <= 0){
            len = node->element.pDataLen;
            if(len <= maxLen){
                memcpy(pData, node->element.pData, len);
            }
            else{
                printf("pData has not enough len for this message\r\n");
            }
            //删除node节点
            preNode->pNext = node->pNext;
            free(node->element.pData);
            free(node);
            node = NULL;
            nodeNum--;
            break;
        }
        preNode = node;
    }
    
    pthread_mutex_unlock(&mMutex);
    
    return len;
}

/**********************************************************************
* 函数名称：CmsgLink::getTimeoutNodeData
* 功能描述：获取一个超时节点的数据
* 输入参数：pData:数据的保存地址指针，需要在此动态分配内存,用完后记得要free掉
* 输出参数：
* 返 回 值：返回数据的长度
* 其它说明：
***********************************************************************/
int CmsgLink::getTimeoutNodeData(void **pData)
{
    int len = -1;
    list_node *node, *preNode;
    if(pNode == NULL) return -1;
    
    //printf("into getTimeoutNodeData\r\n");
    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        if(node->element.timeout <= 0){
            len = node->element.pDataLen;
            *pData = node->element.pData;
            
            //删除node节点
            preNode->pNext = node->pNext;
            free(node);
            node = NULL;
            nodeNum--;
            break;
        }
        preNode = node;
    }
    
    pthread_mutex_unlock(&mMutex);
    //printf("out getTimeoutNodeData\r\n");
    
    return len;
}

int CmsgLink::getTimeoutNodeData(void **pData, void **arg, Callback *callback)
{
    int len = -1;
    list_node *node, *preNode;
    if(pNode == NULL) return -1;
    
    //printf("into getTimeoutNodeData\r\n");
    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        if(node->element.timeout <= 0){
            len = node->element.pDataLen;
            *pData = node->element.pData;
            *arg = node->element.arg;
            *callback = node->element.callback;
                    
            //删除node节点
            preNode->pNext = node->pNext;
            free(node);
            node = NULL;
            nodeNum--;
            break;
        }
        preNode = node;
    }
    
    pthread_mutex_unlock(&mMutex);
    //printf("out getTimeoutNodeData\r\n");
    
    return len;
}

/**********************************************************************
* 函数名称：CmsgLink::getNodeDataById
* 功能描述：通过ID获取一个节点的数据
* 输入参数：pData:数据的保存地址，maxLen:pData最大长度
* 输出参数：
* 返 回 值：返回数据的长度
* 其它说明：
***********************************************************************/
int CmsgLink::getNodeDataById(int id, void *pData, int maxLen)
{
    int len = -1;
    list_node *node, *preNode;
    if((pNode == NULL) || (pData == NULL)) return -1;
    
    pthread_mutex_lock(&mMutex);
    
    for(node = pNode->pNext, preNode = pNode; node != NULL; node = node->pNext){
        if(node->element.id == id){
            len = node->element.pDataLen;
            if(len <= maxLen){
                memcpy(pData, node->element.pData, len);
            }
            else{
                printf("pData has not enough len for this message\r\n");
            }
            //删除node节点
            preNode->pNext = node->pNext;
            free(node->element.pData);
            free(node);
            node = NULL;
            nodeNum--;
            break;
        }
        preNode = node;
    }
    
    pthread_mutex_unlock(&mMutex);
    
    return len;
}


